<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <script src="../../lib/jquery-1.7.2.min.js"></script>
</head>
<body>
<div>
	<h2>Julia Set</h2>
	<br>
	<canvas id="canvas0" height="240" width="480">你的浏览器不支持canvas！</canvas>
</div>
<script>

    class Complex {
        constructor(real, imag) {
            this.real = real;
            this.imag = imag;
        }

        magnitude() {
            return Math.sqrt(this.real * this.real + this.imag * this.imag);
        }
    }

    var canvas = document.getElementById("canvas0");
    var scale = 100.0;
    const cx = canvas.width / 2, cy = canvas.height / 2;
    let ox = 0, oy = 0;
    let c_init = new Complex(-0.5, 0.55);
    const maxIteration = 100;

    // 作者：凡凡的小web
    // 链接：https://www.jianshu.com/p/6c23e62741b7
    // 来源：简书
    // 简书著作权归作者所有，任何形式的转载都请联系作者获得授权并注明出处。
    function hslToRgb(h, s, l) {  
        var r, g, b;        
        if(s == 0){           
            r = g = b = l; // achromatic       
        }else{            
            var hue2rgb = function hue2rgb(p, q, t) {                
                if(t < 0) t += 1;                
                if(t > 1) t -= 1;                
                if(t < 1/6) 
                    return p + (q - p) * 6 * t;               
                if(t < 1/2) 
                    return q;                
                if(t < 2/3) 
                    return p + (q - p) * (2/3 - t) * 6;               
                return p;           
            }            
                var q = l < 0.5 ? l * (1 + s) : l + s - l * s;  
                var p = 2 * l - q;            
                r = hue2rgb(p, q, h + 1/3);            
                g = hue2rgb(p, q, h);           
                b = hue2rgb(p, q, h - 1/3);       
            }       
        return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];    
    }

    function color(value) {
        var h = Math.min(1.0, value);
        var s = 0.9;
        var l = 0.4;
        return hslToRgb(h, s, l);
    }

    function complexMul(a, b) {
        var c = new Complex(0, 0);
        c.real = a.real * b.real - a.imag * b.imag;
        c.imag = a.real * b.imag + b.real * a.imag;
        return c;
    }

    function complexPlus(a, b) {
        return new Complex(a.real + b.real, a.imag + b.imag);
    }

    /* 判断给定点是否在集合内 */
    function inJuliaSet(x, y) {
        var z = new Complex((x - cx) / scale + ox, (y - cy) / scale + oy);
        var c = c_init;
        let i;
        for (i = 0; i < maxIteration && z.magnitude() <= 2; ++i) {
            z = complexPlus(complexMul(z, z), c);
        }
        if (i < maxIteration)
            return [false, i];
        return [true, i];
    }

    function execute() {
        var ctx = canvas.getContext("2d");
		let imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
		let data = imageData.data;
        for (let r = 0; r < canvas.height; ++r) {
            for (let c = 0; c < canvas.width; ++c) {
                let px = r * canvas.width + c;
                if (c === cx || r === cy) {
                    data[px * 4 + 0] = 234;
                    data[px * 4 + 1] = 0;
                    data[px * 4 + 2] = 0;
                    data[px * 4 + 3] = 255;
                }
                else {
                    const res = inJuliaSet(c, r);
                    if (res[0]) {
                        data[px * 4 + 0] = 125;
                        data[px * 4 + 1] = 125;
                        data[px * 4 + 2] = 125;
                        data[px * 4 + 3] = 255;
                    }
                    else {
                        const pxColor = color(Math.pow(res[1] / maxIteration, 0.65));
                        data[px * 4 + 0] = pxColor[0];
                        data[px * 4 + 1] = pxColor[1];
                        data[px * 4 + 2] = pxColor[2];
                        data[px * 4 + 3] = 255;          
                    }
                }
            }
        }
        ctx.putImageData(imageData, 0, 0);
    }

    execute();
    function autoPlay() {
        execute();
        const omega = 1 / 360;
        c_init = complexMul(c_init, new Complex(Math.cos(omega), Math.sin(omega)));
    }
    let intervalHandle = setInterval(autoPlay, 100);

    // 处理滚轮事件
    $(canvas).on('mousewheel DOMMouseScroll', onMouseScroll);
    function onMouseScroll(e){
        e.preventDefault();
        var wheel = e.originalEvent.wheelDelta || -e.originalEvent.detail;
        var delta = Math.max(-1, Math.min(1, wheel));
        if(delta < 0){//向下滚动
            scale /= 1.05;
        }else{//向上滚动
            scale *= 1.05;
        }  
        execute();  
    }

    // 鼠标移动事件
    let mousePrevX, mousePrevY;
    $(canvas).mousemove(function (event) {
        if (event.which) {
            if (mousePrevX && mousePrevY) {
                let dx = event.offsetX - mousePrevX;
                let dy = event.offsetY - mousePrevY;
                ox -= dx / scale;
                oy -= dy / scale;
                execute();
            }
            mousePrevX = event.offsetX;
            mousePrevY = event.offsetY;
        }
        else {
            mousePrevX = mousePrevY = null;
        }
    });
</script>
</body>
</html>